(function (window, document) {
  /**
   * 绘图
   * @param levels {Array} 数据
   * @param id {String}
   */
  var sevenDraw = function (levels, id) {
    document.getElementById(id).innerHTML = '';
    var color = d3.scaleOrdinal(d3.schemeDark2);
    var c = 16;

    function formatData(levels) {
      // precompute level depth
      levels.forEach((l, i) => l.forEach(n => n.level = i))

      var nodes = levels.reduce(((a, x) => a.concat(x)), [])
      var nodes_index = {}
      nodes.forEach(d => nodes_index[d.id] = d)

      // objectification
      nodes.forEach(d => {
        d.parents = (d.parents === undefined ? [] : d.parents).map(p => nodes_index[p])
      })

      // precompute bundles
      levels.forEach((l, i) => {
        var index = {}
        l.forEach(n => {
          if (n.parents.length == 0) {
            return
          }

          var id = n.parents.map(d => d.id).sort().join('--')
          if (id in index) {
            index[id].parents = index[id].parents.concat(n.parents)
          } else {
            index[id] = {id: id, parents: n.parents.slice(), level: i}
          }
          n.bundle = index[id]
        })
        l.bundles = Object.keys(index).map(k => index[k])
        l.bundles.forEach((b, i) => b.i = i)
      })

      var links = []
      nodes.forEach(d => {
        d.parents.forEach(p => links.push({source: d, bundle: d.bundle, target: p}))
      })

      var bundles = levels.reduce(((a, x) => a.concat(x.bundles)), [])

      // layout
      const node_height = 16
      const node_width = 80
      const bundle_width = 16
      const level_y_padding = 16

      var x_offset = 0
      var y_offset = 0
      levels.forEach(l => {
        x_offset += l.bundles.length * bundle_width
        y_offset += level_y_padding
        l.forEach((n, i) => {
          n.x = n.level * node_width + x_offset + node_height / 2
          n.y = i * node_height + y_offset
        })
        y_offset += l.length * node_height
      })

      var i = 0
      levels.forEach(l => {
        l.bundles.forEach(b => {
          b.x = b.parents[0].x + node_width + (l.bundles.length - 1 - b.i) * bundle_width
          b.y = i * node_height
        })
        i += l.length
      })

      links.forEach(l => {
        l.xt = l.target.x
        l.yt = l.target.y
        l.xb = l.bundle.x
        l.yb = l.bundle.y
        l.xs = l.source.x
        l.ys = l.source.y
      })

      var layout = {
        height: nodes.length * node_height + levels.length * level_y_padding,
        width: levels.length * node_width + x_offset + bundle_width,
        node_height,
        node_width,
        bundle_width
      }

      return {levels, nodes, nodes_index, links, bundles, layout}

    }

    var data = formatData(levels);
    console.log(data)

    var svg = d3.select('#' + id)
      .append('svg')
      .attr('class', 'svg')
      .attr('width', data.layout.width)
      .attr('height', data.layout.height);

    var linkG = svg.append('g');
    var textG = svg.append('g');
    var links = linkG.selectAll('path').data(data.links);
    var textWhite = textG.selectAll('text').data(data.nodes);
    var texts = textG.selectAll('text').data(data.nodes);

    var linksEnter = links
      .enter()
      .append('path')
      .attr('d', function (l) {
        var M1 = 'M' + l.xt + ' ' + l.yt;
        var L1 = 'L' + (l.xb - c) + ' ' + l.yt;
        var A1 = 'A' + c + ' ' + c + ' 90 0 1 ' + l.xb + ' ' + (l.yt + c);
        var L2 = 'L' + l.xb + ' ' + (l.ys - c);
        var A2 = 'A' + c + ' ' + c + ' 90 0 0 ' + (l.xb + c) + ' ' + l.ys;
        var L3 = 'L' + l.xs + ' ' + l.ys;
        return M1 + ' ' + L1 + ' ' + A1 + ' ' + L2 + ' ' + A2 + ' ' + L3;
      })
      .attr('fill', 'none')
      .attr('stroke', function (l) {
        return color(l.bundle.id);
      })
      .attr('stroke-width', 2)
      .style('cursor', 'pointer')
      .on('click', function (e, n) {
        console.log(n)
        var source = n.source;
        var target = n.target;
        alert('source -> target: ' + source.id + ' -> ' + target.id)
      })

    links.exit().remove();

    var textsEnter = textWhite
      .enter()
      .append('text')
      .attr('x', function (n) {
        return n.x
      })
      .attr('y', function (n) {
        return n.y
      })
      .attr('dy', '0.35em')
      .style('font-size', function (d) {
        if (d.isHighLight) {
          return '16px'
        }
        return '12px';
      })
      .attr('stroke', '#fff')
      .attr('stroke-width', function (d) {
        return d.isHighLight ? 12 : 6
      })
      .text(function (n) {
        return n.id;
      });
    var textEnter2 = texts
      .enter()
      .append('text')
      .attr('x', function (n) {
        return n.x
      })
      .attr('y', function (n) {
        return n.y
      })
      .attr('dy', '0.35em')
      .style('font-size', function (d) {
        if (d.isHighLight) {
          return '16px'
        }
        return '12px';
      })
      .style('font-weight', function (d) {
        if (d.isHighLight) {
          return '700'
        }
        return '400';
      })
      .text(function (n) {
        return n.id;
      })
      .style('cursor', 'pointer')
      .on('click', function (e, n) {
        console.log(n)
        alert(n.id)
      })

    textWhite.exit().remove();
    texts.exit().remove();
  };
  window.sevenDraw = sevenDraw;
})(window, document)

